﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Segmentator.IntegrityThroughInterval
{
    /// <summary>
    /// Вычисляет минимум симметрии по формуле Шрейдера
    /// </summary>
    class MTChainCapacity:MinSymmetry
    {
        public override double Min(Intervals interval)
        {
            double H1 = 0, H2 = 0;
            double m, n1;

            H1 = capacityGo(interval);  // умножаемое - мощность алфавита
            H2 = capacityGm(interval); // умножаемое - число самых частых сообщений
            return (H1 + H2);
            
        }
        static long Factorial(int n)
        {
            if (n == 0)
                return 1;
            else
                return n * Factorial(n - 1);
        }

        /**
         * Объем по меронам
         */
        public double capacityGm(Intervals interval)
        {
            double[] Vi = new double[interval.ElementAt(0).Count];
            double reducer = 1;
            double G = 1;

            initArray(Vi);

            for (int i = 0; i < Vi.Count(); i++)// число миронов
            {
                for (int j = 0; j < interval.Count; j++)
                {
                    if (i > interval.ElementAt(j).Count - 1) continue;
                    reducer = Math.Log(Factorial(interval.ElementAt(j).ElementAt(i)), 10);
                    Vi[i] = Vi[i] * reducer;
                }
            }

            G = GetG(Vi, G);

            return G;
        }

        /**
         * Объем по таксонам
         */

        public double capacityGo(Intervals interval)
        {
            double[] Vi = new double[interval.Count];
            double G = 1;
            double reducer = 1;
            initArray(Vi);

            for (int i = 0; i < Vi.Count(); i++)
            {
                for (int j = 0; j < interval.ElementAt(i).Count; j++)
                {
                    reducer = Math.Log(Factorial(interval.ElementAt(i).ElementAt(j)), 10);
                    Vi[i] = Vi[i] * reducer;
                }
            }

            G = GetG(Vi, G);

            return G;
        }

        private double GetG(double[] Vi, double G)
        {
            for (int i = 0; i < Vi.Count(); i++)
            {
                G = Vi[i] * G;
            }

            G = Math.Pow(G, 1 / (double)Vi.Count());
            return G;
        }

        private void initArray(double[] Vi)
        {
            for (int i = 0; i < Vi.Count(); i++)
            {
                Vi[i] = 1;
            }
        }
    }
}
